using System;
using System.Collections.Generic;
using System.Text;
using MacomberMap.Common.Components;
using MacomberMap.Common.Database_Interface.CIM.Components;
using System.Xml;

namespace MacomberMap.Common.Database_Interface.CIM.CIM_Interface
{
    /// <summary>
    /// This class holds the information on a trace
    /// </summary>
    public class CIM_TraceList
    {
        #region Variable declarations
        /// <summary>The list of previous elements leading up to this one (usually one)</summary>
        public List<CIM_TraceList> Previous = new List<CIM_TraceList>(10);

        /// <summary>The list of elements following this one</summary>
        public List<CIM_TraceList> Next = new List<CIM_TraceList>(10);

        /// <summary>The base element for the trace</summary>
        public CIM_Element BaseElement;
        #endregion

        #region Initialization
        /// <summary>
        /// Initialize a new CIM tracer list
        /// </summary>
        /// <param name="BaseElement">The CIM element for this item</param>        
        public CIM_TraceList(CIM_Element BaseElement)
        {
            this.BaseElement = BaseElement;
        }
        #endregion

        #region Linkage handling
        /// <summary>
        /// Reciprocally add in the previous linkage
        /// </summary>
        /// <param name="PreviousList"></param>
        private void AddPreviousLinkage(CIM_TraceList PreviousList)
        {
            if (!PreviousList.Next.Contains(this))
                PreviousList.Next.Add(this);
            if (!this.Previous.Contains(PreviousList))
                this.Previous.Add(PreviousList);
        }

        /// <summary>
        /// Parse forward links
        /// </summary>
        /// <param name="Traces">The collection of traces</param>
        /// <param name="PlusOne">Whether we should go one element out after hitting a breaker</param>
        /// <param name="StopNormalOpen">Whether to stop at normally open equipment</param>
        /// <param name="Attribute">The CIM attribute to check, if any </param>
        public void ParseForwardLinks(Dictionary<CIM_Element, CIM_TraceList> Traces, bool PlusOne, bool StopNormalOpen, String Attribute)
        {            
            ParseForwardLinks(Traces, PlusOne, false, StopNormalOpen, Attribute);
        }


        /// <summary>
        /// Recusrively parse all links
        /// </summary>
        /// <param name="PlusOne">Whether we should go out to the next element when we hit a breaker</param>
        /// <param name="Traces">Our collection of traces</param>
        /// <param name="HitBreaker">Whether we've hit a breaker</param>
        /// <param name="StopNormalOpen">Whether to stop at normally open equipment</param>        
        /// <param name="CtgAttribute">The attribute to check (if any)</param>
        private void ParseForwardLinks(Dictionary<CIM_Element, CIM_TraceList> Traces, bool PlusOne, bool HitBreaker, bool StopNormalOpen, string CtgAttribute)
        {
            foreach (CIM_Element Elem in (BaseElement.Type == "cim:ConnectivityNode" ? BaseElement.Elements : BaseElement.Nodes))
                if (Traces.ContainsKey(Elem))
                    this.AddPreviousLinkage(Traces[Elem]);
                else
                {
                    CIM_TraceList NextElem = new CIM_TraceList(Elem);
                    NextElem.AddPreviousLinkage(this);
                    Traces.Add(Elem, NextElem);

                    if (StopNormalOpen && (Elem.Type == "cim:Breaker" || Elem.Type == "cim:Disconnector") && bool.Parse(Elem["cim:Switch.normalOpen"]))
                    { }
                    else
                    {
                        //TODO: This is the change Chad requested, setting the CtgAttribute = false for a switch -> breaker;
                        //bool IsBreaker = Elem.Type == "cim:Breaker" && (String.IsNullOrEmpty(CtgAttribute) || String.IsNullOrEmpty(Elem[CtgAttribute]) || XmlConvert.ToBoolean(Elem[CtgAttribute]));
                        bool IsBreaker = (Elem.Type == "cim:Breaker" && (String.IsNullOrEmpty(CtgAttribute) || String.IsNullOrEmpty(Elem[CtgAttribute]) || XmlConvert.ToBoolean(Elem[CtgAttribute]))) ||
                                    (Elem.Type == "cim:Disconnector" && !String.IsNullOrEmpty(CtgAttribute) && !String.IsNullOrEmpty(Elem[CtgAttribute]) && !XmlConvert.ToBoolean(Elem[CtgAttribute]));
                        if (IsBreaker && PlusOne)
                            NextElem.ParseForwardLinks(Traces, PlusOne, true, StopNormalOpen, CtgAttribute);
                        else if (!IsBreaker && (Elem.Type == "cim:ConnectivityNode" || !HitBreaker))
                            NextElem.ParseForwardLinks(Traces, PlusOne, HitBreaker, StopNormalOpen, CtgAttribute);
                    }
                }
        }
        #endregion

        #region Identifier
        /// <summary>
        /// Offer an easier-to-read string
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return BaseElement.Type.Split(':')[1] + " " + BaseElement.Name;
        }
        #endregion
    }
}

